package com.control.back.halo.bookmark.service.impl;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaBuilder.In;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.control.back.halo.basic.dao.IBaseDao;
import com.control.back.halo.basic.entity.User;
import com.control.back.halo.basic.log4j.Logger;
import com.control.back.halo.basic.service.impl.BaseServiceImpl;
import com.control.back.halo.basic.utils.UserUtils;
import com.control.back.halo.bookmark.dao.ICategoryDao;
import com.control.back.halo.bookmark.dao.IMarkDao;
import com.control.back.halo.bookmark.entity.Category;
import com.control.back.halo.bookmark.entity.Mark;
import com.control.back.halo.bookmark.parse.BrowerMarkHtmlParse;
import com.control.back.halo.bookmark.service.IMarkService;

@Service("markService")
public class MarkServiceImpl extends BaseServiceImpl<Mark, Long> implements IMarkService {

    private static Logger logger = Logger.getLogger(MarkServiceImpl.class);

    @Resource(name = "markDaoImpl")
    IMarkDao markDao;

    @Resource(name = "categoryDaoImpl")
    ICategoryDao categoryDao;

    @Autowired
    BrowerMarkHtmlParse parse;

    @Override
    public IBaseDao<Mark, Long> getBaseDao() {
        return this.markDao;
    }

    public List<Mark> findAll() {
        return markDao.findAllByAuth(UserUtils.getCurrentUser());
//        return super.findAll();
    };

    @Override
    public boolean analysisBrowerMarkHtmlAndSave(InputStream is) {
        try {
            parse.analysisBrowerMarkHtml(is);

            if (parse.getCategorys() == null || parse.getCategorys().isEmpty()) {
                logger.info("catrgory is null!");
            } else {
                categoryDao.save(parse.getCategorys());
            }

            if (parse.getMarks() != null && !parse.getMarks().isEmpty()) {
                markDao.save(parse.getMarks());
            }

            logger.info("parse success!");
            return true;
        } catch (Exception e) {
            logger.error("Document parse is error ", e);
            throw new RuntimeException(e);
        } finally {
            parse.clear();
        }
    }

    @Override
    public Map<String, List<Mark>> findRepeatMark() {
        List<Mark> marks = markDao.findRepeatMark(UserUtils.getCurrentUser().getId());
        Map<String, List<Mark>> markmap = new HashMap<String, List<Mark>>();
        if (marks != null) {
            for (Mark mark : marks) {
                List<Mark> tMarks = markmap.get("T" + mark.getHrefHashCode());
                if (tMarks == null) {
                    tMarks = new ArrayList<Mark>();
                } else {
                    for (Iterator<Mark> iterator = tMarks.iterator(); iterator.hasNext();) {
                        Mark mark2 = iterator.next();
                        if (StringUtils.equals(mark.getCategoryName(), mark2.getCategoryName())) {
                            iterator.remove();
                            markDao.delete(mark2);
                        }
                    }
                }

                tMarks.add(mark);
                markmap.put("T" + mark.getHrefHashCode(), tMarks);
            }
        }

        return markmap;
    }

    @Override
    public void moveMarkToCategory(Long mId, Long categoryId) {
        if (mId != null && categoryId != null) {
            Category category = categoryDao.findOne(categoryId);
            Mark mark = markDao.findOne(mId);

            if (category == null || mark == null) {
                return;
            }
            mark.setCategory(category);
            update(mark);
        }
    }

    @Override
    public Page<Mark> findMarksBy(final String categoryIds, final String name, Pageable pageable) {

        return findAll(new Specification<Mark>() {

            @Override
            public Predicate toPredicate(Root<Mark> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicate = new ArrayList<Predicate>();
                if (StringUtils.isNotBlank(categoryIds)) {
                    In<Long> in = cb.in(root.join("category").get("id").as(Long.class));
                    String[] categoryIdArray = categoryIds.split(",");
                    for (String categoryId : categoryIdArray) {
                        in.value(Long.parseLong(categoryId));
                    }
                    predicate.add(in);
                }

                if (StringUtils.isNotBlank(name)) {
                    Predicate p = cb.like(root.get("name").as(String.class), "%" + name + "%");
                    predicate.add(p);
                }

                User user = UserUtils.getCurrentUser();

                if (user != null) {
                    Predicate p = cb.equal(root.get("createdBy").get("id").as(Long.class), user.getId());
                    predicate.add(p);
                }

                Predicate[] pre = new Predicate[predicate.size()];
                query.where(predicate.toArray(pre));
                return query.getRestriction();
            }
        }, pageable);
    }
}